package com.eddie.auction.web;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author Eddie
 * @date 2022/08/01 15:46
 **/
public class ControllerMappingManager {
    /**
     * 保存Url和java的调用信息
     */
    private final Map<String, ControllerMapping> controllerMappings = new HashMap<>();

    public Map<String, ControllerMapping> getControllerMappings() {
        return controllerMappings;
    }

    /**
     * 构造方法
     */
    public ControllerMappingManager(String configFileName) {
        init(configFileName);
    }

    public void init(String configFileName) {
        InputStream resourceAsStream = this.getClass().getResourceAsStream("/" + configFileName);
        Document doc;
        try {
            //读取映射文件
            doc = new SAXReader().read(resourceAsStream);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
        Element root = doc.getRootElement();
        //查找controllers -> controller元素，并对controller元素进行遍历
        Iterator<Element> controllersIt = root.elements("controllers").iterator();
        Element controllersE1 = controllersIt.next();

        for (Iterator<Element> controllerIt = controllersE1.elementIterator("controller"); controllerIt.hasNext(); ) {
            Element controller = controllerIt.next();
            //获取controller元素中的类型映射信息
            String firstPath = controller.attributeValue("path");
            String className = controller.attributeValue("class");
            if (className.isEmpty()) {
                throw new RuntimeException("Controller映射的信息不能为空!");
            }
            ControllerMapping mapping = null;
            //遍历method元素中的方法映射信息

            for (Iterator<Element> methodIt = controller.elementIterator("method"); methodIt.hasNext(); ) {
                Element method = methodIt.next();
                //获取method元素中的方法映射信息
                String secondPath = method.attributeValue("path");
                String methodName = method.getText();
                if (methodName.isEmpty()) {
                    throw new RuntimeException("方法映射信息不能为空");
                }
                //得到每个方法完整的映射路径
                String fullPath = (firstPath + secondPath).replaceAll("//", "/");
                //检查是否存在重复映射，每个方法调用的映射路径必须是唯一的
                if (controllerMappings.containsKey(fullPath)) {
                    mapping = controllerMappings.get(fullPath);
                    throw new RuntimeException("不能将路径：" + fullPath + "映射到"
                            + className + "." + methodName + "()\n" + "路径"
                            + fullPath + "已被" + mapping.getClassName()
                            + "." + mapping.getMethodName() + "()映射");
                }
                //不重复则将URL和调用信息对应保存在Map中
                mapping = new ControllerMapping(className, methodName);
                controllerMappings.put(fullPath, mapping);
            }
        }
    }

    /**
     * 根据映射信息查询对应的ControllerMapping实例
     */
    public ControllerMapping getControllerMapping(String path) {
        return this.controllerMappings.get(path);
    }

    /**
     * 判断是否存在对应的映射信息
     */
    public boolean containsKey(String path) {
        return this.controllerMappings.containsKey(path);
    }
}
